package com.hzb.LNReader.reader;

import java.io.IOException;
import java.util.concurrent.Semaphore;

import android.util.Log;
import android.view.View;
import android.widget.TextView;

import com.hzb.LNReader.R;
import com.hzb.LNReader.ReaderActivity;
import com.hzb.LNReader.ReaderRecord;
import com.hzb.LNReader.util.ReaderPref;

public class ContentDetector implements Runnable {
	private static final String LOG = ContentDetector.class.getSimpleName();
	private final ReaderView view;
	private final FileReader reader;
	private final ReaderRecord record;
	
	private final int viewFillLine;
	
	private final int screenHeight;
	private final int remainHeight;
	
	
	private Semaphore fillSignal;
	
	private boolean running = true;
	private boolean isPause = true;
	private int paushCount = 2;
	private boolean filling = false;
	
	private int hitCount = 0;
	private int scrollY;
	private int lastScrollY;
	
	private TextView percentTxt;
	
	public ContentDetector(ReaderRecord record, FileReader reader, ReaderView view) {
		this.viewFillLine = ReaderPref.getViewFillLine();
		
		this.record = record;
		this.reader = reader;
		this.view = view;
		this.percentTxt = (TextView) ((ReaderActivity)view.getContext()).findViewById(R.id.ReadProcess);
		this.remainHeight = ((screenHeight = view.getScreenHeight()) << 1);
		this.fillSignal = new Semaphore(0);
	}
	
	public void run() {
		for (;running;) {
			try {
				synchronized (this) {
					if (isPause) {
						this.wait();
					} else {
						if (hitCount == 0) {
							this.wait(1000);
						} else {
							this.wait(150);
						}
//						if (view.getScrollY() == lastScrollY) this.wait(10000); 
					}
					
					scrollY = view.getScrollY();
					if (scrollY > view.getContentHeight() - remainHeight && view.getSeqTo() < record.maxLineSeq) {
						if (!fillContent(true)) continue;
					} else if (scrollY < screenHeight && view.getSeqFrom() > 0) {
						if (!fillContent(false)) continue;
					} else {
						hitCount = 0;
						if (lastScrollY != scrollY) {
							final int percent = view.getPosition()[2];
							percentTxt.post(new Runnable() {
								@Override
								public void run() {
									percentTxt.setText(Integer.toString(percent));
								}
							});
							lastScrollY = scrollY;
						}
						continue;
					}
				}
				
				fillSignal.acquire();
			} catch (Exception e) {
				Log.e(LOG, "Error filling content", e);
				break;
			}
		}
	}
	
	private boolean fillContent(final boolean isAppend) throws IOException, InterruptedException {
		if (scrollY == lastScrollY) {
			if (hitCount == 1) {
				view.post(new Runnable() {
					@Override
					public void run() {
						view.fling(0);
					}
				});
				hitCount ++;
				return false;
			}
		} else {
			lastScrollY = scrollY;
			hitCount = 1;
			return false;
		}
		
		int size = viewFillLine;
		int seqFrom = isAppend ? view.getSeqTo() : view.getSeqFrom() - size;
		
		if (seqFrom < 0) {
			seqFrom = 0;
			size = view.getSeqFrom();
			if (size == 0) {
				return false;
			}
		}
		
		final int[] fillIndex = reader.ensureFileBuffer(seqFrom, size);
		final String[] lineBuffer = reader.contentLine;
		final int[] lineOffset = reader.lineOffset;
		final int limit = lineBuffer.length;
		final int begin = fillIndex[0];
		final int end = fillIndex[1];
		
		View appendar = view.createAppendar(lineOffset[begin]);
		if (appendar == null) return false;
		filling = true;
		
		for (int i=begin;; i++) {
			if (i == limit) i = 0;
			if (i == end) break;
			view.addItem(lineBuffer[i]);
		}
		view.post(new Runnable() {
			@Override
			public void run() {
				synchronized (ContentDetector.this) {
					if (filling) {
						if (isAppend) {
							view.flushAppenderAfter(lineOffset[end]);
						} else {
							view.flushAppenderBefore(lineOffset[end]);
						}
						filling = false;
					}
				}
				fillSignal.release();
			}
		});
		lastScrollY = -1;
		hitCount = 0;
		return true;
	}
	
	public synchronized void start() {
		new Thread(this, "Content Filler").start();
	}
	
	public synchronized void pause() {
		paushCount++;
		if (paushCount == 1) {
			isPause = true;
			if (filling) {
				filling = false;
				view.cancelAppender();
			}
		}
	}
	
	public synchronized void resume() {
		if (0 == --paushCount) {
			isPause = false;
			this.notifyAll();
		}
	}
	
	
	public synchronized void stop() {
		running = false;
		if (filling) {
			filling = false;
			view.cancelAppender();
		}
		this.notifyAll();
	}
}
